作者:萱筱璧 | 来源:互联网 | 2023-10-10 09:57
篇首语:本文由编程笔记#小编为大家整理,主要介绍了入门篇2 # 复杂度分析(下):浅析最好最坏平均均摊时间复杂度相关的知识,希望对你有一定的参考价值。
说明
【数据结构与算法之美】专栏学习笔记。
为什么引入这些时间复杂度
先看下面代码
int find(int[] array, int n, int x)
int i = 0;
int pos = -1;
for (; i < n; &#43;&#43;i)
if (array[i] &#61;&#61; x)
pos &#61; i;
break;
return pos;
上面代码中如果没有 break&#xff1b;那么代码的时间复杂度就是 O(n)&#xff0c;但是代码的循环中存在提前退出循环的操作&#xff0c;普通的时间复杂度分析解决不了这个问题。为了表示代码在不同情况下的不同时间复杂度&#xff0c;就引入了最好、最坏、平均、均摊时间复杂度。
最好、最坏情况时间复杂度
最好情况时间复杂度
&#xff1a;在最理想的情况下&#xff0c;执行代码的时间复杂度。最坏情况时间复杂度
&#xff1a;在最糟糕的情况下&#xff0c;执行代码的时间复杂度。
上面代码在最理想的情况下&#xff0c;查找的变量 x 正好是数组的第一个元素&#xff0c;时间复杂度就是 O(1)&#xff1b;在最糟糕的情况下&#xff0c;就是把整个数组都遍历一遍&#xff0c;时间复杂度就成了 O(n)。
平均情况时间复杂度
最好、最坏比较极端&#xff0c;为了更好地表示平均情况下的复杂度&#xff0c;引入了平均情况时间复杂度。
平均时间复杂度
&#xff1a;又叫加权平均时间复杂度&#xff08;或者期望时间复杂度&#xff09;&#xff0c;用代码在所有情况下执行的次数的加权平均值表示。
上面的代码中查找的变量 x 在数组中的位置&#xff0c;有 n&#43;1 种情况&#xff1a;
- 在数组的 0&#xff5e;n-1 位置中&#xff1a;n 种
- 不在数组中&#xff1a;1 种
假设在数组中与不在数组中的概率都为 1/2&#xff0c;那么出现在 0&#xff5e;n-1 中任意位置的概率就是 1/(2n)。
根据下面等差数列的公式&#xff1a;
1&#43;2&#43;3&#43;…&#43;n &#61; n(1&#43;n)/2
可以快速计算出上面计算式等于(3n &#43; 1)/4
&#xff0c;推出平均时间复杂度为 O(n)。
大多数情况下&#xff0c;不需要区分最好、最坏、平均情况时间复杂度三种情况。只有同一块代码在不同的情况下&#xff0c;时间复杂度有量级的差距&#xff0c;才会使用这三种复杂度表示法来区分。
均摊时间复杂度
下面看一个往数组中插入数据的例子&#xff1a;当数组满了之后&#xff0c;也就是代码中的 count &#61;&#61; array.length
时&#xff0c;用 for 循环遍历数组求和&#xff0c;并清空数组&#xff0c;将求和之后的 sum 值放到数组的第一个位置&#xff0c;然后再将新的数据插入。但如果数组一开始就有空闲空间&#xff0c;则直接将数据插入数组。这里均摊的话不止一次调用 insert 的&#xff0c;可以理解为有外循环。
int[] array &#61; new int[n];
int count &#61; 0;
void insert(int val)
if (count &#61;&#61; array.length)
int sum &#61; 0;
for (int i &#61; 0; i < array.length; &#43;&#43;i)
sum &#61; sum &#43; array[i];
array[0] &#61; sum;
count &#61; 1;
array[count] &#61; val;
&#43;&#43;count;
最理想的情况下&#xff0c;数组中有空闲空间&#xff0c;时间复杂度为 O(1)&#xff1b;最坏的情况下&#xff0c;数组中没有空闲空间&#xff0c;需要遍历一遍&#xff0c;其时间复杂度为 O(n)。
根据数据插入的位置的不同&#xff0c;可以分为 n 种情况&#xff0c;每种情况的时间复杂度是 O(1)。另外一种在数组没有空闲空间时插入一个数据&#xff0c;时间复杂度是 O(n)。这样就有 n &#43; 1 种情况&#xff1a;得到平均时间复杂度为 O(1)。
这里并不需要像之前的平均复杂度分析方法那样&#xff0c;找出所有的输入情况及相应的发生概率&#xff0c;然后再计算加权平均值。针对这种特殊的场景&#xff0c;就引入了一种更加简单的分析方法均摊时间复杂度
&#xff0c;又叫摊还分析&#xff08;或者叫平摊分析&#xff09;。
均摊分析的大致思路&#xff1a;这里对于 insert()
函数来说&#xff0c;O(1) 时间复杂度的插入和 O(n) 时间复杂度的插入&#xff0c;出现的频率是非常有规律的&#xff0c;数组已经满了&#xff0c;也就是 O(n) 是无空闲的状态&#xff0c;每满一次就会清空数组&#xff0c;清空数组后重新开始写 n - 1 次才会进行下一次清空&#xff0c;每次写入的复杂度就是O(1)&#xff0c;有 O(n) 后接着 n - 1 个 O(1)&#xff0c;循环往复。所以把耗时多的那次操作均摊到接下来的 n-1 次耗时少的操作上&#xff0c;均摊下来&#xff0c;这一组连续的操作的均摊时间复杂度就是 O(1)&#xff0c;可以理解为 (n &#43; n - 1)/n。
均摊时间复杂度就是一种特殊的平均时间复杂度&#xff0c;能够应用均摊时间复杂度分析的场合&#xff0c;一般均摊时间复杂度就等于最好情况时间复杂度。